package com.example.fastshareapp;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;



import android.app.Activity;
import android.app.Application;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SyncAdapterType;
import android.content.pm.ComponentInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Rect;
import android.net.Uri;
import android.provider.MediaStore;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.util.Base64;


/**
 * @author Bin Possible
 * 
 */
/**
 * @author Bin Possible
 * 
 */
public class MainApp extends Application implements Observable {

	public static enum Module {
		NONE, GENERAL, USE, HOST
	}

	private static final String TAG = "FastShareApp.MainApp";
	public static String PACKAGE_NAME;

	public static final String ALLJOYN_ERROR_EVENT = "ALLJOYN_ERROR_EVENT";
	public static final String APPLICATION_QUIT_EVENT = "APPLICATION_QUIT_EVENT";
	public static final String HISTORY_CHANGED_EVENT = "HISTORY_CHANGED_EVENT";
	public static final String HOST_CHANNEL_STATE_CHANGED_EVENT = "HOST_CHANNEL_STATE_CHANGED_EVENT";
	public static final String HOST_INIT_CHANNEL_EVENT = "HOST_INIT_CHANNEL_EVENT";
	public static final String HOST_START_CHANNEL_EVENT = "HOST_START_CHANNEL_EVENT";
	public static final String HOST_STOP_CHANNEL_EVENT = "HOST_STOP_CHANNEL_EVENT";
	public static final String OUTBOUND_CHANGED_EVENT = "OUTBOUND_CHANGED_EVENT";
	public static final String USE_CHANNEL_STATE_CHANGED_EVENT = "USE_CHANNEL_STATE_CHANGED_EVENT";
	public static final String USE_JOIN_CHANNEL_EVENT = "USE_JOIN_CHANNEL_EVENT";
	public static final String USE_LEAVE_CHANNEL_EVENT = "USE_LEAVE_CHANNEL_EVENT";
	public static final String PACKAGE_DETAIL_CHANGED_EVENT = "PACKAGE_DETAIL_CHANGED_EVENT";
	public final int HISTORY_MAX = 20;

	private ApplicationService.BusAttachmentState m_busBusAttachmentState;
	private String m_HostChannelName;
	private ApplicationService.HostChannelState m_HostChannelState;
	private String m_UseChannelName;
	private ApplicationService.UseChannelState m_UseChannelState;
	private String m_errorString;
	private List<String> m_listChannels;
	private ComponentName m_runningServer;
	private List<Observer> m_listObserver;
	private ArrayList<Package> m_listOutBound;
	private ArrayList<Package> m_listHistory;
	private ArrayList<PackageDetail> m_listWait;
	private ArrayList<PackageDetail> m_listPackageDetail;
	private Module m_module;

	public void Init() {
		m_busBusAttachmentState = ApplicationService.BusAttachmentState.DISCONNECTED;
		m_HostChannelName = "";
		m_HostChannelState = ApplicationService.HostChannelState.IDLE;
		m_UseChannelName = "";
		m_UseChannelState = ApplicationService.UseChannelState.IDLE;
		m_listChannels = new ArrayList<String>();
		m_runningServer = null;
		m_listObserver = new ArrayList<Observer>();
		m_listOutBound = new ArrayList<Package>();
		m_listHistory = new ArrayList<Package>();
		m_listWait = new ArrayList<PackageDetail>();
		m_listPackageDetail = new ArrayList<PackageDetail>();
		m_module = Module.NONE;

	}

	public synchronized String getM_HostChannelName() {
		return m_HostChannelName;
	}

	public synchronized void setM_HostChannelName(String m_HostChannelName) {
		this.m_HostChannelName = m_HostChannelName;
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
	}

	public synchronized ApplicationService.HostChannelState getM_HostChannelState() {
		return m_HostChannelState;
	}

	public synchronized void setM_HostChannelState(
			ApplicationService.HostChannelState m_HostChannelState) {
		this.m_HostChannelState = m_HostChannelState;
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
	}

	public synchronized String getM_UseChannelName() {
		return m_UseChannelName;
	}

	public synchronized void setM_UseChannelName(String m_UseChannelName) {
		this.m_UseChannelName = m_UseChannelName;
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
	}

	public synchronized ApplicationService.UseChannelState getM_UseChannelState() {
		return m_UseChannelState;
	}

	public synchronized void setM_UseChannelState(
			ApplicationService.UseChannelState m_UseChannelState) {
		this.m_UseChannelState = m_UseChannelState;
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
	}

	public String getM_errorString() {
		return m_errorString;
	}

	public void setM_errorString(String m_errorString) {
		this.m_errorString = m_errorString;
	}

	public synchronized List<String> getM_listChannels() {
		return m_listChannels;
	}

	public synchronized void setM_listChannels(List<String> m_listChannels) {
		this.m_listChannels = m_listChannels;
	}

	public synchronized ArrayList<Package> getM_listOutBound() {
		return m_listOutBound;
	}

	public synchronized void setM_listOutBound(ArrayList<Package> m_listOutBound) {
		this.m_listOutBound = m_listOutBound;
	}

	public synchronized ArrayList<Package> getM_listHistory() {
		return m_listHistory;
	}

	public synchronized void setM_listHistory(ArrayList<Package> m_listHistory) {
		this.m_listHistory = m_listHistory;
	}

	public synchronized ComponentName getM_runningServer() {
		return m_runningServer;
	}

	public synchronized void setM_runningServer(ComponentName m_runningServer) {
		this.m_runningServer = m_runningServer;
	}

	public synchronized Module getM_module() {
		return m_module;
	}

	public synchronized void setM_module(Module m_module) {
		this.m_module = m_module;
	}

	public synchronized ArrayList<PackageDetail> getM_listWait() {
		return m_listWait;
	}

	public synchronized void setM_listWait(ArrayList<PackageDetail> m_listWait) {
		this.m_listWait = m_listWait;
	}
	
	public synchronized ArrayList<PackageDetail> getM_listPackageDetail() {
		return m_listPackageDetail;
	}

	public synchronized void setM_listPackageDetail(
			ArrayList<PackageDetail> m_listPackageDetail) {
		this.m_listPackageDetail = m_listPackageDetail;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Init();
		PACKAGE_NAME = getApplicationContext().getPackageName();
		Intent intent = new Intent(this, Application.class);
		m_runningServer = startService(intent);

	}

	public void quit() {
		m_runningServer = null;
		notifyObserver(APPLICATION_QUIT_EVENT);
	}

	@Override
	public synchronized void addObserver(Observer o) {
		if (m_listObserver.indexOf(o) < 0) {
			m_listObserver.add(o);
		}
	}

	@Override
	public synchronized void deleteObserver(Observer o) {
		if (m_listObserver.indexOf(o) >= 0) {
			m_listObserver.remove(o);
		}
	}

	public synchronized void addFoundChannel(String name) {
		removeFoundChannel(name);
		m_listChannels.add(name);
	}

	public synchronized void removeFoundChannel(String name) {
		for (Iterator<String> channel = m_listChannels.iterator(); channel
				.hasNext();) {
			String channelName = channel.next();
			if (channelName.equals(name)) {
				channel.remove();
			}
		}
	}

	public synchronized Package getOutBoundItem() {
		if (m_listOutBound.isEmpty()) {
			return null;
		} else {
			return m_listOutBound.remove(0);
		}
	}

	public void addHistoryItems(String nickname, Package message)
			throws UnsupportedEncodingException {
		if (m_listHistory.size() > 30) {
			m_listHistory.remove(0);
		}
		m_listHistory.add(message);
		notifyObserver(HISTORY_CHANGED_EVENT);
	}

	public synchronized void removeHistoryItem() {
		for(PackageDetail pac : m_listWait)
		{
			if(pac.m_status.equals("DONE"))
			{
				ArrayList<Package> listDel = new ArrayList<Package>();
				for(Package packageDel : m_listHistory)
				{
					if(packageDel.m_packageName.equals(pac.m_description))
					{
						listDel.add(packageDel);
					}
				}
				for(Package pacDel : listDel)
				{
					m_listHistory.remove(pacDel);
				}
			}
		}
	}

	public void addInboundtems(String nickname, Package message)
			throws UnsupportedEncodingException {
		addHistoryItems(nickname, message);
	}

	public void addOutBoundItems(Package message)
			throws UnsupportedEncodingException {
		if (m_listOutBound.size() > 20) {
			m_listOutBound.remove(0);
		}
		m_listOutBound.add(message);
		notifyObserver(OUTBOUND_CHANGED_EVENT);
	}

	public synchronized void initHostChannel() {
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(HOST_INIT_CHANNEL_EVENT);
	}

	public synchronized void hostStartChannel() {
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(HOST_START_CHANNEL_EVENT);
	}

	public synchronized void hostStopChannel() {
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(HOST_STOP_CHANNEL_EVENT);
	}

	public synchronized void localUserMessage(Package message)
			throws UnsupportedEncodingException {
		addInboundtems("Me", message);
		if (m_UseChannelState == ApplicationService.UseChannelState.JOINED) {
			addOutBoundItems(message);
		}
	}
	
	public synchronized void addRemotePackageDetail(PackageDetail message)
	{
		addWaitPackage(message);
		if (m_UseChannelState == ApplicationService.UseChannelState.JOINED) {
			addRemoteWaitPackage(message);
		}
	}
	
	public synchronized void addRemoteWaitPackage(PackageDetail message)
	{
		if (m_listPackageDetail.size() > 5) {
			m_listPackageDetail.remove(0);
		}
		m_listPackageDetail.add(message);
		notifyObserver(PACKAGE_DETAIL_CHANGED_EVENT);
	}
	
	public synchronized PackageDetail getRemoteWaitPackage()
	{
		if(m_listPackageDetail.size() == 0 )
		{
			return null;
		}
		return m_listPackageDetail.remove(0);
	}
	

	public synchronized void remoteUserMessage(String nickname, Package message)
			throws UnsupportedEncodingException {
		addInboundtems(nickname, message);
	}

	public void notifyObserver(Object obj) {
		for (int i = 0; i < m_listObserver.size(); i++) {
			Observer o = m_listObserver.get(i);
			o.update(this, obj);
		}
	}

	public synchronized void addWaitPackage(PackageDetail packageDetail) {
		if (m_listWait.size() > 5) {
			m_listWait.remove(0);
		}
		m_listWait.add(packageDetail);
	}
	
	public synchronized void removeWaitPackage()
	{
		for(PackageDetail pac : m_listWait)
		{
			if(pac.m_status.equals("DONE"))
			{
				m_listWait.remove(pac);
			}
		}
	}

	public synchronized PackageDetail getWaitPackage() {
		if(m_listWait.size() == 0 )
		{
			return null;
		}
		return m_listWait.get(0);
	}

	public synchronized Boolean CheckSendStatus() {
		if(m_listWait.size()== 0)
		{
			return false;
		}
		PackageDetail pacDe = m_listWait.get(0);
		int count = 0;

		for (Package pac : m_listHistory) {
			if (pacDe.m_description.equals(pac.m_packageName)) {
				count++;
			}
		}
		if (count == pacDe.m_numPackage) {
			pacDe.m_status = "DONE";
			m_listWait.get(0).m_status =  "DONE";
			return true;
		}
		else
		{
			return false;
		}
		
	}

	public synchronized void useJoinChannel() {
		clearHistoryList();
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(USE_JOIN_CHANNEL_EVENT);
	}

	public synchronized void useLeaveChannel() {
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(USE_LEAVE_CHANNEL_EVENT);
	}

	public void clearHistoryList() {
		m_listHistory.clear();
		notifyObserver(HISTORY_CHANGED_EVENT);
	}

	public void chechIn() {
		if (m_runningServer == null) {
			Intent intent = new Intent(this, ApplicationService.class);
			m_runningServer = startService(intent);
		}
	}

	public void manageError(Module module, String error) {
		m_module = module;
		m_errorString = error;
		notifyObserver(ALLJOYN_ERROR_EVENT);
	}
	
	

	

}
